package com.sj.server;

import com.sj.pojo.FirstProtocol;
import com.sj.pojo.MsgTypeEnum;
import com.sj.pojo.Protocol;
import com.sj.utils.TransferUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * Created with IntelliJ IDEA.
 * User: xiaoqi
 * Date: 2022-07-07
 * Time: 上午 11:16
 * Description: 传输服务器
 *
 * @author xiaoqi
 * @since 2022-07-07
 */
public class TransferServer {

    public static void main(String[] args) {
        try {
            Selector selector = Selector.open();
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(7005));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("服务器已就绪");
            listen(selector, serverSocketChannel);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 监听请求
     *
     * @param selector
     * @throws IOException
     */
    public static void listen(Selector selector, ServerSocketChannel serverSocketChannel) {
        for (; ; ) {
            int requestCount = 0;
            try {
                requestCount = selector.select();
                // 如果请求数量为0 继续监听
                if (requestCount == 0) {
                    continue;
                }

                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = keys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    iterator.remove();
                    //判断是连接请求还是读请求
                    if (selectionKey.isAcceptable()) {
                        // 请求操作
                        acceptOperation(selector, serverSocketChannel);
                    }

                    if (selectionKey.isReadable()) {
                        // 读操作
                        readOperation(selector, selectionKey);
                    }
                }
            } catch (IOException e) {
                System.out.println("有连接断开");
            }
        }
    }

    /**
     * 读操作
     *
     * @param selector
     * @param selectionKey
     */
    private static void readOperation(Selector selector, SelectionKey selectionKey) {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        try {
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ);
            Protocol protocol = TransferUtils.receive(socketChannel);

            Protocol res = distinguishInstruct(protocol);

            TransferUtils.send(res, socketChannel);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 辨别指令，处理数据
     *
     * @param protocol
     * @return
     */
    private static Protocol distinguishInstruct(Protocol protocol) {
        Protocol isNormal = NormalInstruct.operationInstruct(protocol.getContent());
        return isNormal != null ? isNormal : OperationInstruct.operationInstruct(protocol.getContent());
    }

    /**
     * 请求连接操作
     * <p>
     * 加入到选择器中，并且监听读
     *
     * @param selector
     * @param serverSocketChannel
     */
    private static void acceptOperation(Selector selector, ServerSocketChannel serverSocketChannel) {
        try {
            SocketChannel socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ);
            FirstProtocol firstProtocol = new FirstProtocol();
            Protocol protocol = firstProtocol.getProtocol(MsgTypeEnum.RESPONSE, "已成功连接");

            // 发送消息
            TransferUtils.send(protocol, socketChannel);

        } catch (IOException e) {
            System.out.println("有连接断开accept");
        }
    }

}